package com.holyland.service;

import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Query;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang.StringUtils;

import com.holyland.model.Matrix;
import com.holyland.model.Member;
import com.holyland.model.User;
import com.holyland.util.HolylandException;
import com.holyland.util.HolylandUtil;
import com.holyland.util.MailUtil;

import static com.holyland.util.IHolylandConstants.MAX_MEMBER;

public class MemberService {
	private static MemberService instance;
	
	protected MemberService() {
		
	}
	
	public static MemberService getInstance() {
		if(instance == null) {			
			instance = new MemberService();				
		}
		
		return instance;
	}
	
	public void createMember(Member member) throws HolylandException { 
		EntityManagerFactory ef = EMF.get();
		EntityManager em = ef.createEntityManager();		
		
		try {			
			
			// check parent one level up						
			Long parentId = member.getParentId();
			
			if(parentId != null && parentId != null) {
				Member parent = findMemberById(parentId);
				
				if(parent != null) {
					Integer currMember = parent.getCurrMember() + 1;										
					
					parent.setCurrMember(currMember);
					
					em.persist(parent);
							
					// check parent two level up
					Long parentId2 = parent.getParentId();
					
					if(parentId2 != null && parentId2 != 0) {
						Member grandParent = findMemberById(parentId2);
						
						if(grandParent != null) {
							Integer currMember2 = grandParent.getCurrMember() + 1;
							
							grandParent.setCurrMember(currMember2);																					
							
							if(currMember2 == MAX_MEMBER) {
								
								List<Member> members = searchMemberByParentId(grandParent.getId());
								
								for (Member level1 : members) {
									level1.setParentId(null);
									level1.setCurrMember(3);
									em.persist(level1);
								}
								
								grandParent.setCycledOut(true);
								grandParent.setCurrMember(0);
								MailUtil.sendEmail("hbc.indonesia@gmail.com", "HBC Admin", "Info member yang cycled out", constructEmailMsgCycledOut(grandParent.getName(), grandParent.getEmail(), grandParent.getMobile()));
							}
							
							em.persist(grandParent);
						}
					}					
				}
			}
						
			member.setCurrMember(0);
			
			em.persist(member);				
			em.refresh(member);
			
			String generatedPswd = HolylandUtil.generatePswd();
			String email = member.getEmail();
			String name = member.getName();
			
			User user = new User();			
			user.setUsername(email);			
			user.setPassword(generatedPswd);			
			user.setName(name);
			user.setMemberId(member.getId());
			user.setFirstTimeLogin(true);
			
			createUser(user);			
			
			// send email
			MailUtil.sendEmail(email, name, "Konfirmasi Pendaftaran", constructEmailMsg(name, email, generatedPswd));
													
			
		} catch(Exception e) {
			e.printStackTrace();
			throw new HolylandException();
		} finally {
			em.close();
		}							
	}	
	
	private String constructEmailMsgCycledOut(String name, String username, String telp) {
		StringBuilder sb = new StringBuilder();
		
		sb.append("Kepada Admin ").append("<br><br>");
		sb.append("<p>");
		sb.append("Peserta berikut telah cycled out, silakan dicek informasi berikut: <br><br>");
		sb.append("<ul>");
		sb.append("<li>").append("Nama pengguna: ").append("<b>").append(username).append("</b></li>");
		sb.append("<li>").append("Nama lengkap: ").append("<b>").append(name).append("</b></li>");
		sb.append("<li>").append("Telp: ").append("<b>").append(telp).append("</b></li>");
		sb.append(" </ul>");		
		sb.append("</p>");
				
		sb.append("Dari<br>System");		
		
		return sb.toString();
	}
	
	private String constructEmailMsg(String name, String username, String password) {
		StringBuilder sb = new StringBuilder();
		
		sb.append("Kepada Yth. ").append(name).append("<br><br>");
		sb.append("<p>");
		sb.append("Kami telah menyelesaikan proses registrasi saudara. Sekarang saudara dapat melihat matriks anggota saudara dengan login ke <a href=\"http://hbcindonesia.appspot.com\">http://hbcindonesia.appspot.com</a> dengan menggunakan informasi berikut: <br><br>");
		sb.append("<ul>");
		sb.append("<li>").append("Nama pengguna: ").append("<b>").append(username).append("</b></li>");
		sb.append("<li>").append("Kata kunci: ").append("<b>").append(password).append("</b></li>");
		sb.append(" </ul>");		
		sb.append("</p>");
				
		sb.append("Hormat kami<br>PT. HBC Admin");		
		
		return sb.toString();
	}
	
	public void createUser(User user) throws HolylandException { 
		EntityManager em = EMF.get().createEntityManager();
		
		try {
			em.persist(user);			
		} catch(Exception e) {
			e.printStackTrace();
			throw new HolylandException();
		} finally {
			em.close();
		}
	}
	
	public User findUserById(Long id) throws HolylandException {
		EntityManager em = EMF.get().createEntityManager();
		User found = null;
		
		try {
			found = em.find(User.class, id);
		} catch(Exception e) {
			throw new HolylandException(e.getMessage());
		} finally {
			em.close();
		}
				
		return found;
	}
	
	public User editUser(User user) throws HolylandException {
		EntityManager em = EMF.get().createEntityManager();
		
		User edited = null;
		
		try {
			edited = findUserById(user.getUserId());			
			BeanUtils.copyProperties(edited, user);
			
			em.persist(edited);
			
		} catch (IllegalAccessException e) {			
			e.printStackTrace();
			throw new HolylandException();
		} catch (InvocationTargetException e) {			
			e.printStackTrace();
			throw new HolylandException();
		} finally {
			em.close();
		}
		
		return edited;
	}
	
	@SuppressWarnings("unchecked")
	public User findUserByUserName(String username) throws HolylandException {
		User user = null;
		EntityManager em = EMF.get().createEntityManager();
		
		try {					
			String query = "select from User where username = :prmUserName";
			
			Query q = em.createQuery(query);
			q.setParameter("prmUserName", username);
			
			List<User> temp = q.getResultList();
			
			if(temp != null && !temp.isEmpty()) {
				user = temp.get(0);
			}
		} catch (Exception e) {			
			e.printStackTrace();
			throw new HolylandException();
		} finally {
			em.close();
		}
		
		return user;
	}
	
	@SuppressWarnings("unchecked")
	public List<Member> searchMember(Member member) {
		List<Member> listResult = null;		
		EntityManager em = EMF.get().createEntityManager();
		
		try {
			String query = "select from Member where cycledOut = " + member.isCycledOut();									
			
			if(StringUtils.isNotBlank(member.getName())) {
				query += " and name = :prmName";				
			}
			
			if(StringUtils.isNotBlank(member.getEmail())) {
				query += " and email = :prmEmail";				
			}						
			
			Query q = em.createQuery(query);
			
			if(StringUtils.isNotBlank(member.getName())) {
				q.setParameter("prmName", member.getName());
			}
			
			if(StringUtils.isNotBlank(member.getEmail())) {
				q.setParameter("prmEmail", member.getEmail());
			}
			
			listResult = q.getResultList();			
			listResult.size();
						
			return listResult;
			
		} finally {
			em.close();
		}				
	}
	
	@SuppressWarnings("unchecked")
	public List<Member> searchParentMemberByEmail(String email) {
		List<Member> listResult = null;
		
		EntityManager em = EMF.get().createEntityManager();
		
		try {
			String query = "select from Member where email = :prmEmail";
			
			Query q = em.createQuery(query);
			q.setParameter("prmEmail", email);
						
			listResult = q.getResultList();
			listResult.size();
			
			return listResult;
		} finally {
			em.close();
		}
	}		
	
	public Member findMemberById(Long id) throws HolylandException {
		EntityManager em = EMF.get().createEntityManager();
		
		Member found = null;
		
		try {
			found = em.find(Member.class, id);
		} catch (Exception e) {
			throw new HolylandException(e.getMessage());
		} finally {
			em.close();
		}
		
		return found;
	}
		
	public Matrix searchMatrix(Long parentId) throws HolylandException {
		Matrix matrix = null;
		
		if(parentId != null) {													
			List<Member> listLevel1 = searchMemberByParentId(parentId);
			
			if(listLevel1 != null && !listLevel1.isEmpty()) {
				
				matrix = new Matrix();					
				matrix.setParentId(parentId);
				matrix.setLevel1(listLevel1);
				
				Map<Long, List<Member>> mapLevel2 = new HashMap<Long, List<Member>>();
								
				for (Member member : listLevel1) {
					Long id = member.getId();
					
					List<Member> listLevel2 = searchMemberByParentId(id);					
					mapLevel2.put(member.getId(), listLevel2);
				}
				
				matrix.setLevel2(mapLevel2);
			}																		
		}	
		
		return matrix;
	}
	
	@SuppressWarnings("unchecked")
	public List<Member> searchMemberByParentId(Long parentId) throws HolylandException {
		List<Member> listResult = null;
		
		EntityManager em = EMF.get().createEntityManager();
		
		try {
			String query = "select from Member where parentId = " + parentId;
			
			Query q = em.createQuery(query);			
			listResult = q.getResultList();
			
			listResult.size();
			
			return listResult;		
		} finally {
			em.close();
		}				
	}
	
	public Member editMember(Member member) throws HolylandException {
		EntityManager em = EMF.get().createEntityManager();
		
		Member edited = null;
		
		try {
			edited = findMemberById(member.getId());
			BeanUtils.copyProperties(edited, member);						
			
			em.persist(edited);
			
		} catch (IllegalAccessException e) {
			e.printStackTrace();
			throw new HolylandException();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
			throw new HolylandException();
		} finally {
			em.close();
		}
				
		return edited;		
	}
}
